package net.ssta.core.db;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.ssta.core.code.JsonEncodeAdapter;
import net.ssta.core.util.format.ValueObjectFormat;

/**
 * 
 * @author qiuzhl
 */
public class Record
{
	private String m_entityName;
	private List<String> m_primaryKey = new ArrayList<String>();
	private Map<String,Object> m_data = new HashMap<String,Object>();
//	private Map<String,String> m_column_type = null;
	
	private DataBaseExecutor m_executor = null;

	public Record() {}

	/**
	 * �����ݿ�l�Ӻ�ʵ�����ʵ��Record����
	 * @param conn ��ȡ�õ���Ч����ݿ�l��
	 * @param entityName Ҫ�������ݿ�ʵ����ƣ�����
	 */
	public Record(Connection conn, String entityName)
	{
		setConnection(conn);
		this.m_entityName = entityName;
	}

	/**
	 * �����ݿ�l�Ӻ�ʵ�����ʵ��Record������ʵ���ͬʱָ�����
	 * @param conn ��Ч����ݿ�l��
	 * @param entityName ʵ�壨�?�����
	 * @param primaryKey ʵ�壨�?�����
	 */
	public Record(Connection conn, String entityName, String primaryKey)
	{
		setConnection(conn);
		this.m_entityName = entityName;
		this.m_primaryKey.add(primaryKey);
	}
	
	/**
	 * ������ݿ�l��
	 * @param conn ��Ч����ݿ�l��
	 */
	public void setConnection(Connection conn)
	{
		m_executor = DataBaseExecutor.getExecutor(conn);
	}
	
	public Connection getConnection(){return m_executor == null ? null : m_executor.getConnection();}
	
	/**
	 * ����ʵ�����
	 * @param entityName ��ݿ��д��ڵ�ʵ�壨�?�����
	 */
	public void setEntityName(String entityName)
	{
		m_entityName = entityName.toUpperCase();
	}
	
	/**
	 * ��ȡ��ʵ���Ӧ��ʵ�壨�?�����
	 * @return
	 */
	public String getEntityName(){	return m_entityName; }
	
	/**
	 * ΪRecordʵ�����һ�����ò�����Ϊ��ֵ����Ӱ���Ѿ����õ����
	 * @param pk ��Ϊ���������
	 */
	public void addPrimaryKey(String pk)
	{
		m_primaryKey.add(pk.toUpperCase());
	}
	
	/**
	 * ΪRecordʵ�����һ�����ò�����Ϊ��ֵ����Ӱ���Ѿ����õ����
	 * @param keys һ���������
	 */
	public void addPrimaryKey(String[] keys)
	{
		for(int i=0; i<keys.length; i++)
		{
			m_primaryKey.add(keys[i].toUpperCase());
		}
	}

	/**
	 * ΪRecordʵ����������ʵ��ֻ����һ������ʱ��ʹ�ã��ò�����Ϊ��ֵ��ԭ4��������
	 * @param pk ��Ϊ���������
	 */
	public void setPrimaryKey(String pk)
	{
		m_primaryKey.clear();
		m_primaryKey.add(pk.toUpperCase());
	}
	
	/**
	 * ΪRecordʵ������һ�����ò�����Ϊ��ֵ��ԭ4��������
	 * @param keys һ���������
	 */
	public void setPrimaryKey(String[] keys)
	{
		m_primaryKey.clear();
		for(int i=0; i<keys.length; i++)
		{
			m_primaryKey.add(keys[i].toUpperCase());
		}
	}
	
	/**
	 * �Ƴ�Recordʵ����������
	 */
	public void removePrimaryKey() 
	{
		m_primaryKey.clear();
	}

	/**
	 * �Ƴ�Recordʵ���һ�����
	 * @param pk ���Ƴ���������
	 */
	public void removePrimaryKey(String pk) 
	{
		m_primaryKey.remove(pk.toUpperCase());
	}
	
	/**
	 * �Ƴ�Recordʵ���һ�����
	 * @param keys ���Ƴ�������������
	 */
	public void removePrimaryKey(String[] keys) 
	{
		for(int i=0; i<keys.length; i++)
		{
			m_primaryKey.remove(keys[i].toUpperCase());
		}
	}
	
	/**
	 * ȡ��Recordʵ���к��е������е����
	 * @return
	 */
	public String[] getFields(){ return m_data.keySet().toArray(new String[0]); }
	
	/**
	 * ��Recordʵ�����ֵΪ������������з������ļ�¼�����ø÷����ǣ�������Ҫ�ƶ�һ�����
	 * @return
	 * @throws SQLException
	 */
	public RecordSet find() throws SQLException
	{
		return m_executor.find(this, null, null,null);
	}
	
	/**
	 * ��Recordʵ�����ֵΪ������������з������ļ�¼�����ø÷���ʱ��������Ҫָ��һ�����
	 * @param selectColumns ָ����ѯ��Ҫ����Щ��
	 * @return
	 * @throws SQLException
	 */
	public RecordSet find(String[] selectColumns) throws SQLException
	{
		return m_executor.find(this, selectColumns, null,null);
	}
	
	/**
	 * ��Recordʵ�����ֵΪ������������з������ļ�¼�����ø÷���ʱ��������Ҫָ��һ�����
	 * @param selectColumns ָ����ѯ��Ҫ����Щ��
	 * @param order ָ����ѯ��������ʽ��ÿ������Ԫ�صĸ�ʽΪ columnName asc/desc������asc����ʡ��
	 * @return
	 * @throws SQLException
	 */
	public RecordSet find(String[] selectColumns, String[] order) throws SQLException
	{
		return m_executor.find(this, selectColumns, order,null);
	}
	
	/**
	 * ��Recordʵ�����ֵΪ������������з������ļ�¼�����ø÷���ʱ��������Ҫָ��һ�����
	 * @param selectColumns ָ����ѯ��Ҫ����Щ��
	 * @param order ָ����ѯ��������ʽ��ÿ������Ԫ�صĸ�ʽΪ columnName asc/desc������asc����ʡ��
	 * @param PagingInfo pagingInfo ��ҳ��Ϣ
	 * @return
	 * @throws SQLException
	 */
	public RecordSet find(String[] selectColumns, String[] order,PagingInfo pagingInfo) throws SQLException
	{
		return m_executor.find(this, selectColumns, order,pagingInfo);
	}
	
	/**
	 * ��Recordʵ���������е�ֵΪ��������ø÷���ʱ�����е�����ж�����Ϊ��ֵ
	 * @param columns ָ����ѯ��Ҫ����Щ��
	 * @return
	 * @throws SQLException
	 */
	public Record findByPrimaryKey() throws SQLException
	{
		return m_executor.findByPrimaryKey(this, null);
	}

	/**
	 * ��Recordʵ���������е�ֵΪ��������ø÷���ʱ�����е�����ж�����Ϊ��ֵ
	 * @param columns ָ����ѯ��Ҫ����Щ��
	 * @return
	 * @throws SQLException
	 */
	public Record findByPrimaryKey(String[] columns) throws SQLException
	{
		return m_executor.findByPrimaryKey(this, columns);
	}
	
	/**
	 * ��ȡָ���ֶε�ֵ
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public Object getObjectValue(String fieldName) { return m_data.get(fieldName); }

	/**
	 * ���ֽ�����ķ�ʽ�����ֶε�ֵ��������ʧ�ܣ��򷵻�NULL�����ֵΪ�գ��򷵻�new byte[0]
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public byte[] getBytes(String fieldName)
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getBytes(obj);
	}

	/**
	 * ���ַ�ķ�ʽ�����ֶε�ֵ
	 * @param fieldName fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public String getString(String fieldName) 
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getString(obj,"");
	}
	
	/**
	 * ���ַ�����ķ�ʽ�����ֶε�ֵ��ֻ��ֵΪ�ַ���ֶβſ��Ե��ø÷�����������׳��쳣
	 * @param fieldName fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public String[] getStringArray(String fieldName) 
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getStringArray(obj);
	}
	
	/**
	 * ���ַ�ķ�ʽ�����ֶε�ֵ�����ֵΪ�գ��򷵻�defaultValue
	 * @param fieldName fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @param defaultValue
	 * @return
	 */
	public String getString(String fieldName, String defaultValue) 
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getString(obj,defaultValue);
	}
	
	/**
	 * ���ַ�ķ�ʽ�����ֶε�ֵ������б�Ҫ������formatString���и�ʽ�������ֵΪ�գ��򷵻�defaultValue
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @param defaultValue
	 * @param formatString
	 * @return
	 */
	public String getString(String fieldName, String defaultValue, String formatString) 
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getString(obj,defaultValue,formatString);
	}
	
	/**
	 * ��INT�ķ�ʽ�����ֶε�ֵ�����ֵΪ�գ��򷵻�0
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public int getInt(String fieldName)
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getInt(obj);
	}

	/**
	 * ��FLOAT�ķ�ʽ�����ֶε�ֵ�����ֵΪ�գ��򷵻�0
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public float getFloat(String fieldName)
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getFloat(obj);
	}

	/**
	 * ��LONG�ķ�ʽ�����ֶε�ֵ�����ֵΪ�գ��򷵻�0
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public long getLong(String fieldName)
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getLong(obj);
	}

	/**
	 * ��DOUBLE�ķ�ʽ�����ֶε�ֵ�����ֵΪ�գ��򷵻�0
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public double getDouble(String fieldName)
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getDouble(obj);
	}
	
	/**
	 * ��Date�ķ�ʽ�����ֶε�ֵ�����ֵΪ�գ��򷵻�0
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @return
	 */
	public Date getDate(String fieldName)
	{
		Object obj = getObjectValue(fieldName);
		ValueObjectFormat formatter = ValueObjectFormat.getFormat(obj);
		return formatter.getJavaUtilDate(obj, "yyyy-MM-dd");
	}
	
	/**
	 * ΪRecordʵ��������ֶΣ��˲���Ḳ���Ѿ����ڵ�ͬ���ֶ�
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 * @param fieldValue  ���ֵ
	 */
	public void addData(String fieldName, Object fieldValue)
	{
//		setColumnType(fieldName, ( fieldValue == null ) ? "null" : fieldValue.getClass().getName());
		m_data.put(fieldName, fieldValue);
	}
	

	/**
	 * ΪRecordʵ��������ֶΣ��˲���Ḳ���Ѿ����ڵ�ͬ���ֶ�
	 * @param datas ���ֵ
	 */
	public void addData(Map<String, Object> datas)
	{
		Object[] keys = datas.keySet().toArray();
		for (int i = 0; i < keys.length; i++)
		{
			String fieldName = ((String) keys[i]).toUpperCase();
			Object fieldValue = datas.get(keys[i]);
//			setColumnType(fieldName, ( fieldValue == null ) ? "null" : fieldValue.getClass().getName());
			m_data.put(fieldName, fieldValue);
		}
	}

	/**
	 * �Ƴ�Recordʵ������ֶ�
	 * @param fieldName �ֶε���ƣ�����Ϊ��д����ֵ����Ϊ��
	 */
	public void removeData(String fieldName)
	{
		m_data.remove(fieldName);
		m_primaryKey.remove(fieldName);
	}

	/**
	 * �Ƴ�Recordʵ������ֶ�
	 * @param fields �ֶε�������飬����Ϊ��д����ֵ����Ϊ��
	 */
	public void removeData(String[] fields)
	{
		for (int i = 0; i < fields.length; i++)
		{
			m_data.remove(fields[i]);
			m_primaryKey.remove(fields[i]);
		}
	}

	public String toString() 
	{
		return this.m_data.toString();
	}
	
	private boolean isNewRecord()
	{
		boolean bRet = false;		
		for (int i = 0; i < m_primaryKey.size() && (bRet == false); i++) 
		{
			String pk = m_primaryKey.get(i);
			Object pkValue = m_data.get(pk);
			bRet = bRet || pkValue == null || "".equals(pkValue) || "null".equals(pkValue);
		}
		return bRet;
	}
	
	/**
	 * ��ʵ�壨�?�����һ���¼�����Record���ڿ�ֵ���������Զ���UUID���
	 * @return
	 * @throws SQLException
	 */
	public Record create() throws SQLException
	{
		m_executor.create(this);
		return this;
	}
	
	/**
	 * ��Recordʵ���е���ݸ��µ�ʵ�壨�?�ж�Ӧ�ļ�¼�У����Record���ڿ�ֵ���������׳��쳣
	 * @return
	 * @throws SQLException
	 */
	public Record update() throws SQLException
	{
		m_executor.update(this);
		return this;
	}
	
	/**
	 * ��Recordʵ���е���ݱ��浽ʵ�壨�?�У����Record���ڿ�ֵ�������ִ��create�������ִ��update����
	 * @return
	 * @throws SQLException
	 */
	public Record store() throws SQLException
	{
		if(isNewRecord())
		{
			m_executor.create(this);
		}
		else
		{
			if(m_executor.update(this) == 0)
			{
				m_executor.create(this);
			}
		}
		return this;
	}

	/**
	 * ��Recordʵ���е���ݴ�ʵ�壨�?��ɾ�����Record���ڿ�ֵ���������׳��쳣
	 * @return
	 * @throws SQLException
	 */
	public int remove() throws SQLException
	{
		return m_executor.delete(this);
	}
	
	public String getJsonString()
	{
		StringBuffer sb = new StringBuffer();
		sb.append("{ ");
		String[] fields = getFields();
		for(int i = 0; i<fields.length; i++)
		{
			String f = fields[i];
			String s = getString(f, "");
			if(!"".equals(s))
			{
				sb.append("'").append(f.toLowerCase()).append("':'").append(escape4json(s)).append("',");
			}
		}
		sb.setCharAt(sb.length()-1, '}');
		return sb.toString();
	}
	
	
	public String getJsonString(JsonEncodeAdapter adapter)
	{
		StringBuffer sb = new StringBuffer();
		sb.append("{ ");
		String[] fields = getFields();
		for(int i = 0; i<fields.length; i++)
		{
			String f = fields[i];
			String s = getString(f, "");
			if(!"".equals(s))
			{
				sb.append("'").append(f.toLowerCase()).append("':").append(adapter.encode(f, s)).append(",");
			}
		}
		sb.setCharAt(sb.length()-1, '}');
		return sb.toString();
	}
	
	private String escape4json(String sv)
	{
		return sv.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'").replaceAll("\"", "\\\\\"").replaceAll("\r", "\\\\r").replaceAll("\n", "-n-n-n");
		//return sv.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'").replaceAll("\"", "\\\\\"").replaceAll("\r", "\\\\r").replaceAll("\n", "\\\\n");
	}
	
	Iterator<String> primaryKeyIterator()
	{
		return m_primaryKey.iterator();
	}
	
	boolean containsPrimaryKey(String pk)
	{
		return m_primaryKey.contains(pk);	
	}
	
	String[] getPrimaryKeyFields(){ return m_primaryKey.toArray(new String[0]); }
	
}
